﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace FileCompareByHash
{
    using ErkerTech.DeltaScope.App.Models;
    using ErkerTech.DeltaScope.Engine;
    using ErkerTech.DeltaScope.View;
    using ErkerTech.DeltaScope.View.Controls;
    using ErkerTech.DeltaScope.View.Models;
    using FileCompareByHash;
    public partial class TextDiffForm : Form
    {

        #region Private Declarations
        private readonly SwirlController _swirlController;
        private readonly List<SwirlBlock> _blockList;
        #endregion

        public FileInfo _file1;
        public FileInfo _file2;

        public TextDiffForm(FileInfo file1, FileInfo file2)
            : this()
        {
            _file1 = file1;
            _file2 = file2;

            _txtFile1.Text = _file1.FullName;
            _txtFile2.Text = _file2.FullName;

            DeltaScopeApp.SwirlFontChanged += ((sender, e) =>
            {
                _swirlController.Font = DeltaScopeApp.SwirlFont;
                _swirlDisplay.Refresh();
            });
            DeltaScopeApp.WordWrapChanged += ((sender, e) =>
            {
                _swirlController.WordWrap = DeltaScopeApp.WordWrap;
                _swirlDisplay.Refresh();
            });
            DeltaScopeApp.SwirlRegionVisibleChanged += ((sender, e) =>
            {
                _swirlDisplay.ShowSwirlRect = DeltaScopeApp.SwirlRegionVisible;
            });

            _blockList = new List<SwirlBlock>();
            _swirlController = new SwirlController(_swirlDisplay, _blockList);

        }
        #region Public Methods
        public void Bind(IList<DeltaBlock> deltaBlockList)
        {
            _blockList.Clear();
            // Loop through all the blocks...
            foreach (var loBlock in deltaBlockList)
                _blockList.Add(new SwirlBlock(loBlock));

            // Bind the controller to the control...			
            _swirlController.Bind();

            //Bind the Histogram to the same BlockList...
            _blockHistogram.Blocks = _blockList;
        }
        #endregion
        public TextDiffForm()
        {
            InitializeComponent();
        }
        #region local event handlers
        private void BlockHistogramClickHandler(object sender, EventArgs e)
        {
            var lnCurrentBlock = _blockHistogram.CurrentBlockIndex;
            if (lnCurrentBlock >= 0) _swirlController.JumpToBlock(lnCurrentBlock);
        }
        #endregion
        private void _btnOK_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void _btnBinaryComp_Click(object sender, EventArgs e)
        {
            try
            {

                bool bSame = FileCompareByHashExtension.MultiFileCompareByHash.FilesContentsAreEqual(_file1, _file2);
                string msg = string.Format(bSame ? "The files '{0}' and '{1}' are identical.{2}Do you want to see more details?" : "The files '{0}' and '{1}' are different.{2}Do you want to see more details?",
                    Path.GetFileName(_file1.Name), Path.GetFileName(_file2.Name), Environment.NewLine);
                // bool bIsBinary = item == _binaryCompareItem || item == _binaryCompare2Items;
                DialogResult res = DialogResult.No;

                res = MessageBox.Show(this, msg, "Binary comparison results", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                if (res == DialogResult.Yes)
                {

                    using (Form frm = (Form)new DetailedComparison(_file1, _file2, bSame))
                    {

                        frm.ShowDialog(this);
                    }

                }
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message, "Error");
            }
        }

        private void TextDiffForm_Load(object sender, EventArgs e)
        {
            _txtFile1.BackColor = _blockHistogram.LeftColor;
            _txtFile2.BackColor = _blockHistogram.RightColor;
            _txtFile1.Select(0,0);
            RefreshDiff();
            return;
          
        }

        private void RefreshDiff()
        {
            _btnRefresh.Enabled = false;
            _blockHistogram.Blocks = null;
            _blockHistogram.BackColor = System.Drawing.SystemColors.ScrollBar;
            UseWaitCursor = true;
            Color bcolor = _swirlDisplay.BackColor;
            _txtLevensthein.Text = string.Format("Calculating Levensthein distance...");
            _txtLevensthein.BackColor = Color.Gray;
            _swirlDisplay.BackColor = System.Drawing.SystemColors.ScrollBar;
            Application.DoEvents();
            var loDeltaBlocks = DeltaScopeApp.Engine.Compare(_file1.FullName, _file2.FullName, _ckBoxCaseing.Checked);
            if (loDeltaBlocks != null)
                Bind(loDeltaBlocks);
            _swirlDisplay.BackColor = bcolor;

            // Start a task - this runs on the background thread...
            var levtask = Task.Factory.StartNew(() =>
            {
                double diff = -1;

                try
                {
                    string txt1 = File.ReadAllText(_file1.FullName);
                    string txt2 = File.ReadAllText(_file2.FullName);

                   // diff = Levensthein.Differentiation(txt1, txt2, true,  x => Math.Asin(x) * 2 / Math.PI);//stays in 0..1 range
                  //  diff = Levensthein.Differentiation(txt1, txt2, false, x => Math.Sin(x * Math.PI / 2));//stays in 0..1 range
                    diff = Levensthein.Differentiation(txt1, txt2, _ckBoxCaseing.Checked);//diff stays in 0..1 range
                }
                catch (Exception ex)
                {
                    diff = -1;
                    Levensthein.Reset();//clear the mem
                }

                return diff;
            });

            var context = TaskScheduler.FromCurrentSynchronizationContext();
            //updateUI
            Task next = levtask.ContinueWith(tr =>
            {

                double errs = tr.Result;
                if (errs >= 0)
                {
                    try
                    {
                        _txtLevensthein.Text = string.Format("File similarity using Levensthein distance = {0:N2}%", 100 * (1.0 - errs));
                        if (errs < .10)
                            _txtLevensthein.BackColor = Color.LightGreen;
                        else
                            if (errs > .5)
                                _txtLevensthein.BackColor = Color.LightPink;
                            else
                                _txtLevensthein.BackColor = Color.Yellow;
                       // Application.DoEvents();
                        _blockHistogram.BackColor = _txtLevensthein.BackColor;

                    }
                    catch (Exception ex)
                    {
                        _txtLevensthein.Text = string.Format("Can't calculate Levensthein distance: {0}%", ex.Message);
                        _txtLevensthein.BackColor = Color.LightPink;
                        _blockHistogram.BackColor = System.Drawing.SystemColors.ScrollBar;
                    }
                }
                else
                {
                    _txtLevensthein.Text = string.Format("Can't calculate Levensthein distance");
                    _txtLevensthein.BackColor = Color.LightPink;
                    _blockHistogram.BackColor = System.Drawing.SystemColors.ScrollBar;
                }
                _btnRefresh.Enabled = true;
                this.UseWaitCursor = false;
                //_btnRefresh.Focus();
                //Application.DoEvents();
            }

             , context);
            
        }


        private void _btnRefresh_Click(object sender, EventArgs e)
        {
            RefreshDiff();
        }
    }
}
